package com.econ.powercloud.ems.service.biz;

import com.alibaba.fastjson.JSON;
import com.econ.powercloud.clickhouse.entity.EmsFaultData;
import com.econ.powercloud.common.base.facade.util.JacksonUtil;
import com.econ.powercloud.ems.common.enums.*;
import com.econ.powercloud.ems.common.util.KeepDecimalPointUtil;
import com.econ.powercloud.ems.constant.SysConstant;
import com.econ.powercloud.ems.dal.entity.*;
import com.econ.powercloud.ems.pojo.*;
import com.econ.powercloud.ems.pojo.scene.OpenApiHisDataVO;
import com.econ.powercloud.ems.service.common.QueryCalDataCommonService;
import com.econ.powercloud.ems.service.common.QueryFlashDataCommonService;
import com.econ.powercloud.ems.service.dao.*;
import com.econ.powercloud.ems.util.BMSKindUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author : zjf
 * @Description : 新版实时数据查询service
 * @Date : 2021/11/17 17:36
 * @Modified by : zjf
 */
@Service
public class FlashNewDataService {

    @Autowired
    private EmsDeviceDAO emsDeviceDAO;
    @Autowired
    private EmsProductLocationConfigDAO emsProductLocationConfigDAO;
    @Autowired
    private QueryFlashDataCommonService queryFlashDataCommonService;
    @Autowired
    private EmsYkYtShowService emsYkYtShowService;
    @Autowired
    private EmsDeviceCalConfigDAO emsDeviceCalConfigDAO;
    @Autowired
    private QueryCalDataCommonService queryCalDataCommonService;
    @Autowired
    private ClickHouseBizService clickHouseBizService;
    @Autowired
    IotProductYkYtDitDAO iotProductYkYtDitDAO;


    /**
     * 查询实时数据,并按照量测类型,pid进行分组
     */
    public Map<String, FlashDataVO> getFlashMap(List<EmsDeviceLocationVO> deviceLocationList){
        List<FlashDataVO> flashVOS = queryFlashDataCommonService.getFlashData(JacksonUtil.convertToList(deviceLocationList, QueryDataVO.class));
        if(CollectionUtils.isEmpty(flashVOS)){
            return Collections.EMPTY_MAP;
        }
        return flashVOS.stream().collect(Collectors.toMap(FlashDataVO::getPid, p -> p));
    }

    /**
     * 获取实时数据
     * @param locationVO : 需要获取的实时数据的封装类
     * @param flashVOMap : 实时数据查询结果Map
     */
    public FlashVO getFlashVO(EmsDeviceLocationVO locationVO, Map<String, FlashDataVO> flashVOMap){
        if(locationVO == null){
            return FlashVO.builder().build();
        }
        LocationUrl locationUrl = LocationUrl.fromCode(locationVO.getLocation());
        FlashVO flashVO = FlashVO.builder().pid(locationVO.getPid()).initDeviceCode(locationVO.getInitDeviceCode())
                .ditType(locationUrl == null?null : locationUrl.getDitTypeEnum().getCode())
                .dit(locationVO.getDit())
                .name(locationVO.getName()).unit(locationVO.getUnit()).build();
        //获取查询的实时数据
        FlashDataVO vo = flashVOMap.get(locationVO.getPid());
        if (vo != null) {
            flashVO.setTime(vo.getTime());
            flashVO.setValue(vo.getVal());
            flashVO.setUnit(vo.getUnit());
        }
        return flashVO;
    }

    /**
     * 查询计算点号数据(可能包含实测点号，故需要分开查询),并按照pid进行分类
     */
    public Map<String, FlashDataVO> getCalFlashMap(List<EmsDeviceCalLocationVO> locationVOList){
        Map<String, FlashDataVO> result = Maps.newHashMap();
        List<FlashDataVO> calFlashVOS = queryCalDataCommonService.getCalData(JacksonUtil.convertToList(locationVOList.stream().filter(d-> VirtualType.VIRTUAL.getCode().equals(d.getVirtual())).collect(Collectors.toList()), QueryDataVO.class));
        List<FlashDataVO> realFlashVOS = queryFlashDataCommonService.getFlashData(JacksonUtil.convertToList(locationVOList.stream().filter(d-> VirtualType.REAL.getCode().equals(d.getVirtual())).collect(Collectors.toList()), QueryDataVO.class));
        if(CollectionUtils.isEmpty(calFlashVOS) && CollectionUtils.isEmpty(realFlashVOS)){
            return result;
        }
        List<FlashDataVO> flashVOS = Lists.newArrayList();
        if(CollectionUtils.isNotEmpty(calFlashVOS)){
            flashVOS.addAll(calFlashVOS);
        }
        if(CollectionUtils.isNotEmpty(realFlashVOS)){
            flashVOS.addAll(realFlashVOS);
        }
        result.putAll(flashVOS.stream().collect(Collectors.toMap(FlashDataVO::getPid, p -> p)));
        return result;
    }

    /**
     * 组装计算数据返回对象
     * @param locationVO : 需要获取的实时数据的封装类
     * @param flashVOMap : 实时数据查询结果Map
     */
    public FlashVO getCalFlashVO(EmsDeviceCalLocationVO locationVO, Map<String, FlashDataVO> flashVOMap){
        if(locationVO == null){
            return FlashVO.builder().build();
        }
        FlashVO flashVO = FlashVO.builder().pid(locationVO.getPid()).initDeviceCode(locationVO.getInitDeviceCode())
                .dit(locationVO.getDit())
                .name(locationVO.getName()).build();
        //获取查询的实时数据
        FlashDataVO vo = flashVOMap.get(locationVO.getPid());
        if(vo == null){
            return flashVO;
        }
        flashVO.setTime(vo.getTime());
        flashVO.setDitType(vo.getDitType());
        if(ComplexEnums.COMPLEX.getCode().equals(locationVO.getComplex())){
            PidInfoVO pidInfoVO = JSON.parseObject(vo.getVal(), PidInfoVO.class);
            flashVO.setValue(pidInfoVO.getVal());
            flashVO.setExtraInfo(BMSKindUtil.getClusterByCondition(pidInfoVO));
            flashVO.setUnit(vo.getUnit());
        }else {
            flashVO.setValue(vo.getVal());
            flashVO.setUnit(vo.getUnit());
        }
        return flashVO;
    }

    /**
     * 位置信息分组，组装数据
     * @param deviceLocationList: 数据源
     * @param flashMap: 实时数据map
     */
    private List<List<FlashVO>> dealWithDeviceLocationByColumn(List<EmsDeviceLocationVO> deviceLocationList,
                                                               Map<String, FlashDataVO> flashMap){
        List<List<FlashVO>> result = Lists.newArrayList();
        //按照行进行分组
        Map<Integer, List<EmsDeviceLocationVO>> flashUrlMap = deviceLocationList.stream().collect(Collectors.groupingBy(f -> f.getColumn()));
        //分别获取每一列中数据
        for (int i = 1; i <= flashUrlMap.keySet().size(); i++) {
            List<FlashVO> voList = Lists.newArrayList();
            //按照一列中的行大小升序排序
            List<EmsDeviceLocationVO> flashList = flashUrlMap.get(i).stream().sorted(Comparator.comparing(EmsDeviceLocationVO::getRow)).collect(Collectors.toList());
            flashList.stream().forEach(g -> {
                voList.add(this.getFlashVO(g,flashMap));
            });
            result.add(voList);
        }
        return result;
    }

    /**
     * 封装需要查询的计算点号数据
     * @param emsDevice 设备信息
     * @param configList 对应需要查询的数据
     */
    public List<EmsDeviceCalLocationVO> getCalLocationVOByLocationAndConfig(EmsDevice emsDevice, List<EmsDeviceCalConfig> configList){
        List<EmsDeviceCalLocationVO> result = Lists.newArrayList();
        if(CollectionUtils.isEmpty(configList)){
            return result;
        }
        configList.stream().forEach(d->{
            result.add(EmsDeviceCalLocationVO.builder()
                    .pid(d.getComputeCode()).deviceCode(emsDevice.getDeviceCode())
                    .initDeviceCode(emsDevice.getInitDeviceCode()).deviceName(d.getName())
                    .dit(d.getComputeCode().replace(emsDevice.getInitDeviceCode() + SysConstant.SPOT,""))
                    .location(d.getLocation()).measureType(d.getMeasureType()).name(d.getName())
                    .sorting(d.getSorting()).complex(d.getComplex())
                    .virtual(d.getVirtual())
                    .build());
        });
        return result;
    }

    /**
     * 封装需要查询的实时数据
     *
     * @param emsDevice:           设备信息
     * @param configList：对应需要查询的数据
     * @return
     */
    public List<EmsDeviceLocationVO> getDeviceLocationVOByLocationAndConfig(EmsDevice emsDevice, List<EmsProductLocationConfig> configList) {
        List<EmsDeviceLocationVO> result = Lists.newArrayList();
        if (CollectionUtils.isEmpty(configList)) {
            return result;
        }
        configList.stream().forEach(d -> {
            Integer column = null; //行
            Integer row = null; //列
            if (d.getSorting() != null) {
                String[] locations = d.getSorting().split(SysConstant.CABLE);
                //赋值坐标位置,如果不是二维坐标,就认为都是一行的
                row = Integer.parseInt(locations[0]);
                column = locations.length > 1 ? Integer.parseInt(locations[1]) : SysConstant.ONE_INTEGER;
            }
            result.add(EmsDeviceLocationVO.builder()
                    .pid(emsDevice.getInitDeviceCode() + SysConstant.SPOT + d.getDit())
                    .deviceCode(emsDevice.getDeviceCode())
                    .productKey(d.getProductKey()).moduleCode(d.getModuleCode()).dit(d.getDit())
                    .initDeviceCode(emsDevice.getInitDeviceCode()).virtual(d.getVirtual())
                    .location(d.getLocation()).measureType(d.getMeasureType()).name(d.getName())
                    .sorting(d.getSorting()).column(column).row(row)
                    .unit(d.getUnit())
                    .build());
        });
        return result;
    }

    /**
     * 获取储能站首页计算数据
     * @param stationId 储能站id
     */
    public List<FlashVO> getHomePageInfo(String stationId){
        //通过储能站id获取储能站设备code
        List<EmsDevice> emsDeviceList = emsDeviceDAO.getListByCondition(stationId,null, DeviceType.STATION.getCode());
        if(CollectionUtils.isEmpty(emsDeviceList)){
            return Collections.EMPTY_LIST;
        }
        EmsDevice stationDevice = emsDeviceList.get(0);
        //获取该储能站设备对应的计算点号有哪些
        List<EmsDeviceCalConfig> calConfigList = emsDeviceCalConfigDAO.selectListByLocationAndDeviceCode(stationDevice.getDeviceCode(), CalLocationType.HOME_PAGE.getCode());
        List<EmsDeviceCalLocationVO> locationVOList = this.getCalLocationVOByLocationAndConfig(stationDevice,calConfigList);
        if(CollectionUtils.isEmpty(locationVOList)){
            return Collections.EMPTY_LIST;
        }
        List<FlashVO> result = Lists.newArrayList();
        locationVOList = locationVOList.stream().sorted(Comparator.comparing(EmsDeviceCalLocationVO::getSorting)).collect(Collectors.toList());
        //调用接口查询计算点号数据
        Map<String, FlashDataVO> calFlashMap = this.getCalFlashMap(locationVOList);
        locationVOList.stream().forEach(d->{
            result.add(this.getCalFlashVO(d,calFlashMap));
        });
        return result;
    }

    /**
     * 根据deviceCode获取该设备对应的二维遥测数据
     */
    public List<List<FlashVO>> getDeviceTwoDimensionalYcData(String deviceCode){
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, FaultDesc.FAILURE_NOT_FOUNT.getDesc());
        Map<String, Map<String, List<EmsProductLocationConfig>>> locationMap = emsProductLocationConfigDAO.getMapByLocation(LocationUrl.TWO_DIMENSIONAL_YC.getCode());
        if(MapUtils.isEmpty(locationMap)){
            return Collections.emptyList();
        }
        //组装自己需要获取的实时数据信息
        List<EmsProductLocationConfig> configList = locationMap.get(emsDevice.getProductKey()).get(emsDevice.getModuleCode());
        if(CollectionUtils.isEmpty(configList)){
            return Collections.emptyList();
        }
        List<EmsDeviceLocationVO> deviceLocationList = this.getDeviceLocationVOByLocationAndConfig(emsDevice, configList);
        //调用查询实时数据接口
        Map<String, FlashDataVO> flashMap = this.getFlashMap(deviceLocationList);
        if(CollectionUtils.isEmpty(deviceLocationList)){
            return Collections.EMPTY_LIST;
        }
        return this.dealWithDeviceLocationByColumn(deviceLocationList,flashMap);
    }

    /**
     * 获取PCS/PCU遥信数据
     * @param deviceCode: PCS设备code
     */
    public PCSOrPCUYxVO getPCSOrPCUYxDataByDeviceCode(String deviceCode) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, FaultDesc.FAILURE_NOT_FOUNT.getDesc());
        Map<String, Map<String, List<EmsProductLocationConfig>>> locationMap = emsProductLocationConfigDAO.getMapByLocations(
                Lists.newArrayList(LocationUrl.STATE_YX.getCode(), LocationUrl.FAULT_YX.getCode(), LocationUrl.ALARM_YX.getCode()));
        //组装自己需要获取的实时数据信息
        List<EmsProductLocationConfig> configList = locationMap.get(emsDevice.getProductKey()).get(emsDevice.getModuleCode());
        List<EmsDeviceLocationVO> locationVOList = this.getDeviceLocationVOByLocationAndConfig(emsDevice, configList);
        if(CollectionUtils.isEmpty(locationVOList)){
            return PCSOrPCUYxVO.builder().name(emsDevice.getDeviceName()).stateFlashVOS(Collections.EMPTY_LIST).faultFlashVOS(Collections.EMPTY_LIST).alarmFlashVOS(Collections.emptyList()).build();
        }
        //调用查询实时数据接口
        Map<String, FlashDataVO> flashMap = this.getFlashMap(locationVOList);
        Map<Integer,Object> locationTypeMap = this.getDeviceDataGroupByLocation(locationVOList,flashMap);
        Object alarmObj = locationTypeMap.get(LocationUrl.ALARM_YX.getCode());
        Object faultObj = locationTypeMap.get(LocationUrl.FAULT_YX.getCode());
        return PCSOrPCUYxVO.builder().name(emsDevice.getDeviceName())
                .alarmFlashVOS(alarmObj == null?Collections.emptyList():(List<FlashVO>)alarmObj)
                .faultFlashVOS(faultObj == null?Collections.emptyList():(List<FlashVO>)faultObj)
                .stateFlashVOS(locationTypeMap.get(LocationUrl.STATE_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.STATE_YX.getCode()))
                .build();
    }

    /**
     * 设置flashVO动画状态
     * @param alarmOrFaultObj
     */
    private List<FlashVO> setAnimateForFaultOrAlarm(Object alarmOrFaultObj) {
        if (alarmOrFaultObj!=null){
            List<FlashVO> alarmOrFaultVOS = (List<FlashVO>) alarmOrFaultObj;
            List<String> pids = alarmOrFaultVOS.stream().filter(d-> YxValueType.break_position.getCode().toString().equals(d.getValue())).map(FlashVO::getPid).collect(Collectors.toList());
            if (pids.size()==0){
                return alarmOrFaultVOS;
            }
            //30日内的故障告警数据查询
            List<EmsFaultData> emsFaultList = clickHouseBizService.findFaultListByPid(pids, EventSourceType.YX.getCode());
            Map<String,List<EmsFaultData>> faultMap = emsFaultList.stream().collect(Collectors.groupingBy(EmsFaultData::getFaultPid,
                    Collectors.collectingAndThen(Collectors.toList(), list -> list.stream().sorted(Comparator.comparingLong(EmsFaultData::getGmtCreate).reversed())
                            .collect(Collectors.toList()))));
            alarmOrFaultVOS.forEach(d->{
                if (faultMap.get(d.getPid())!=null){
                    //如果最新的故障告警未处理（dealState=0）则需要闪灯
                    d.setAnimate(faultMap.get(d.getPid()).get(0).getDealState().equals(0)? AnimateType.LIGHT_FLICKER.getCode():AnimateType.NORMAL.getCode());
                }
            });
            return alarmOrFaultVOS;
        }
        return Collections.emptyList();
    }

    /**
     * @deprecated
     * 低压储能站下的所有BAMS的统计数据
     * @param stationId: 储能站id
     */
    public List<FlashVO> getLowStationBAMSStaticalData(String stationId){
        //通过储能站id获取储能站设备code
        List<EmsDevice> emsDeviceList = emsDeviceDAO.getListByCondition(stationId,null, DeviceType.STATION.getCode());
        if(CollectionUtils.isEmpty(emsDeviceList)){
            return Collections.EMPTY_LIST;
        }
        EmsDevice stationDevice = emsDeviceList.get(0);
        //获取该储能站设备对应的计算点号有哪些
        List<EmsDeviceCalConfig> calConfigList = emsDeviceCalConfigDAO.selectListByLocationAndDeviceCode(stationDevice.getDeviceCode(), CalLocationType.BMS_MAX_OR_MIN_DATA.getCode());
        List<EmsDeviceCalLocationVO> locationVOList = this.getCalLocationVOByLocationAndConfig(stationDevice,calConfigList);
        if(CollectionUtils.isEmpty(locationVOList)){
            return Collections.EMPTY_LIST;
        }
        List<FlashVO> result = Lists.newArrayList();
        locationVOList = locationVOList.stream().sorted(Comparator.comparing(EmsDeviceCalLocationVO::getSorting)).collect(Collectors.toList());
        //调用接口查询计算点号数据
        Map<String, FlashDataVO> calFlashMap = this.getCalFlashMap(locationVOList);
        locationVOList.stream().forEach(d->{
            result.add(this.getCalFlashVO(d,calFlashMap));
        });
        return result;
    }

    /**
     * 高压储能站的BMS的统计数据
     * @param stationId: 储能站id
     */
    public List<List<FlashVO>> getHighStationBAMSStaticalData(String stationId,String equipmentId){
        //通过储能站id获取储能装置BMS设备
        List<EmsDevice> deviceList = emsDeviceDAO.getListByCondition(stationId,equipmentId, DeviceType.EQUIPMENT_BMS.getCode());
        if(CollectionUtils.isEmpty(deviceList)){
            return Collections.EMPTY_LIST;
        }
        //默认只能有一个
        return this.getBAMSStaticalData(deviceList.get(0));
    }

    /**
     * 获取单个BAMS的统计数据
     * @return
     */
    public List<List<FlashVO>> getSingleBAMSStaticalData(String deviceCode){
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice,"设备不存在！");
        return this.getBAMSStaticalData(emsDevice);
    }

    public List<List<FlashVO>> getBAMSStaticalData(EmsDevice emsDevice){
        Map<String, Map<String, List<EmsProductLocationConfig>>> locationMap = emsProductLocationConfigDAO.getMapByLocation(LocationUrl.TWO_DIMENSIONAL_YC.getCode());
        //组装自己需要获取的实时数据信息
        List<EmsDeviceLocationVO> locationVOList = Lists.newArrayList();
        //不为真实设备也不做处理
        if(StringUtils.isEmpty(emsDevice.getProductKey()) || StringUtils.isEmpty(emsDevice.getModuleCode())){
            return Collections.EMPTY_LIST;
        }
        List<EmsProductLocationConfig> configList = Lists.newArrayList();
        if(MapUtils.isNotEmpty(locationMap.get(emsDevice.getProductKey())) &&
                CollectionUtils.isNotEmpty(locationMap.get(emsDevice.getProductKey()).get(emsDevice.getModuleCode()))){
            configList.addAll(locationMap.get(emsDevice.getProductKey()).get(emsDevice.getModuleCode()));
        }
        locationVOList.addAll(this.getDeviceLocationVOByLocationAndConfig(emsDevice, configList));
        //按照设备code分组,key:设备id
        Map<String, List<EmsDeviceLocationVO>> locationVOMap = locationVOList.stream().collect(Collectors.groupingBy(d -> d.getDeviceCode()));
        //调用查询实时数据接口
        Map<String, FlashDataVO> flashMap = this.getFlashMap(locationVOList);
        List<EmsDeviceLocationVO> locationVOS = locationVOMap.get(emsDevice.getDeviceCode());
        List<List<FlashVO>> flashVOList = this.dealWithDeviceLocationByColumn(locationVOS,flashMap);
        return flashVOList;
    }

    /**
     * 获取低压BMS下的所有簇的实时数据信息
     */
    public List<ClusterKindVO> getLowBMSClusterData(String stationId, String equipmentId) {
        List<ClusterKindVO> result = Lists.newArrayList();
        //获取所有的簇设备
        List<EmsDevice> clusterDeviceList = emsDeviceDAO.getListByCondition(stationId, equipmentId, DeviceType.CLUSTER.getCode());
        Map<String, Map<String, List<EmsProductLocationConfig>>> locationMap = emsProductLocationConfigDAO.getMapByLocation(LocationUrl.ONE_DIMENSIONAL_YC.getCode());
        //组装自己需要获取的实时数据信息
        List<EmsDeviceLocationVO> locationVOList = Lists.newArrayList();
        clusterDeviceList.stream().forEach(d -> {
            List<EmsProductLocationConfig> configList = locationMap.get(d.getProductKey()).get(d.getModuleCode());
            locationVOList.addAll(this.getDeviceLocationVOByLocationAndConfig(d, configList));
        });
        //按照设备code分组,key:设备id
        Map<String, List<EmsDeviceLocationVO>> locationVOMap = locationVOList.stream().collect(Collectors.groupingBy(d -> d.getDeviceCode()));
        //调用查询实时数据接口
        Map<String, FlashDataVO> flashMap = this.getFlashMap(locationVOList);
        clusterDeviceList.stream().forEach(d -> {
            List<FlashVO> flashVOList = Lists.newArrayList();
            List<EmsDeviceLocationVO> deviceLocationList = locationVOMap.get(d.getDeviceCode());
            if (CollectionUtils.isNotEmpty(deviceLocationList)) {
                deviceLocationList = deviceLocationList.stream().sorted(Comparator.comparing(EmsDeviceLocationVO::getRow)).collect(Collectors.toList());
                deviceLocationList.stream().forEach(f -> {
                    FlashVO flashVO = this.getFlashVO(f,flashMap);
                    flashVO.setTag(SysConstant.TABLE_LOGO + f.getRow());
                    flashVOList.add(flashVO);
                });
            }
            result.add(ClusterKindVO.builder().name(d.getDeviceName()).deviceCode(d.getDeviceCode()).ycFlashVO(flashVOList).build());
        });
        return result;
    }

    /**
     * 获取高压储能装置下的单元体信息
     */
    public List<PhaseKindVO> getHighBMSClusterData(String stationId,String equipmentId) {
        //获取所有的簇设备与相设备
        List<EmsDevice> deviceList = emsDeviceDAO.getListByStationIdAndEquipmentIdAndDeviceTypes(stationId, equipmentId, Lists.newArrayList(DeviceType.CLUSTER.getCode(),DeviceType.PHASE.getCode()));
        Map<Integer,List<EmsDevice>> deviceMap = deviceList.stream().collect(Collectors.groupingBy(d->d.getDeviceType(), LinkedHashMap::new,Collectors.toList()));
        //获取所有的簇设备
        List<EmsDevice> clusterDeviceList = deviceMap.get(DeviceType.CLUSTER.getCode());
        if(CollectionUtils.isEmpty(clusterDeviceList)){
            return Collections.emptyList();
        }
        //获取三相设备信息
        List<EmsDevice> phaseDeviceList = deviceMap.get(DeviceType.PHASE.getCode());
        return this.dealWithClusterData(phaseDeviceList,clusterDeviceList);
    }

    /**
     * 获取某个BMS下的单元体信息
     * @param deviceCode: BMS设备编号
     */
    public List<PhaseKindVO> getClusterDataByBamsCode(String deviceCode){
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice,"设备不存在！");
        //查询该BMS下的相设备有哪些
        List<EmsDevice> phaseDeviceList = emsDeviceDAO.getChildDeviceByCondition(deviceCode,DeviceType.PHASE.getCode());
        if(CollectionUtils.isEmpty(phaseDeviceList)){
            return Collections.emptyList();
        }
        //获取簇设备有哪些
        List<EmsDevice> clusterDeviceList = emsDeviceDAO.getListByStationIdAndEquipmentIdAndDeviceTypes(emsDevice.getEnergyStationId(),
                emsDevice.getEnergyEquipmentId(), Lists.newArrayList(DeviceType.CLUSTER.getCode()));
        return this.dealWithClusterData(phaseDeviceList,clusterDeviceList);
    }

    /**
     * 获取相下面的簇的单元体信息
     * @param deviceCode: 相设备编号
     */
    public List<ClusterKindVO> getClusterDataByPhase(String deviceCode){
        EmsDevice phaseDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(phaseDevice,"相设备不存在");
        List<EmsDevice> clusterList = emsDeviceDAO.getChildDeviceByCondition(deviceCode,DeviceType.CLUSTER.getCode());
        if(CollectionUtils.isEmpty(clusterList)){
            return Collections.emptyList();
        }
        List<PhaseKindVO> phaseKindVOList = this.dealWithClusterData(Lists.newArrayList(phaseDevice),clusterList);
        if(CollectionUtils.isEmpty(phaseKindVOList)){
            return Collections.emptyList();
        }
        return phaseKindVOList.get(0).getClusterKindVOS();
    }

    /**
     * 处理单元体信息
     * @param phaseDeviceList : 相设备集合
     * @param clusterDeviceList ：簇设备集合
     * @return
     */
    public List<PhaseKindVO> dealWithClusterData(List<EmsDevice> phaseDeviceList,List<EmsDevice> clusterDeviceList){
        List<PhaseKindVO> result = Lists.newArrayList();
        if(CollectionUtils.isEmpty(phaseDeviceList)){
            return Collections.emptyList();
        }
        //簇按照相分组,key:相设备code
        Map<String,List<EmsDevice>> clusterMap = clusterDeviceList.stream().collect(Collectors.groupingBy(d->d.getParentDeviceCode(), LinkedHashMap::new,Collectors.toList()));
        Map<String, Map<String, List<EmsProductLocationConfig>>> locationMap = emsProductLocationConfigDAO.getMapByLocation(LocationUrl.ONE_DIMENSIONAL_YC.getCode());
        //组装自己需要获取的实时数据信息
        List<EmsDeviceLocationVO> locationVOList = Lists.newArrayList();
        clusterDeviceList.stream().forEach(d -> {
            List<EmsProductLocationConfig> configList = locationMap.get(d.getProductKey()).get(d.getModuleCode());
            locationVOList.addAll(this.getDeviceLocationVOByLocationAndConfig(d, configList));
        });
        //按照设备code分组,key:设备id
        Map<String, List<EmsDeviceLocationVO>> locationVOMap = locationVOList.stream().collect(Collectors.groupingBy(d -> d.getDeviceCode()));
        //调用查询实时数据接口
        Map<String, FlashDataVO> flashMap = this.getFlashMap(locationVOList);
        phaseDeviceList.stream().forEach(pahse ->{
            List<ClusterKindVO> clusterList = Lists.newArrayList();
            List<EmsDevice> emsDevices = CollectionUtils.isNotEmpty(clusterMap.get(pahse.getDeviceCode()))?clusterMap.get(pahse.getDeviceCode()):Lists.newArrayList();
            emsDevices.stream().forEach(d -> {
                List<FlashVO> flashVOList = Lists.newArrayList();
                List<EmsDeviceLocationVO> deviceLocationList = locationVOMap.get(d.getDeviceCode());
                if (CollectionUtils.isNotEmpty(deviceLocationList)) {
                    deviceLocationList = deviceLocationList.stream().sorted(Comparator.comparing(EmsDeviceLocationVO::getRow)).collect(Collectors.toList());
                    deviceLocationList.stream().forEach(f -> {
                        FlashVO flashVO = this.getFlashVO(f,flashMap);
                        flashVO.setTag(SysConstant.TABLE_LOGO + f.getRow());
                        flashVOList.add(flashVO);
                    });
                }
                clusterList.add(ClusterKindVO.builder().name(d.getDeviceName()).deviceCode(d.getDeviceCode()).ycFlashVO(flashVOList).build());
            });
            result.add(PhaseKindVO.builder().name(pahse.getDeviceName()).deviceCode(pahse.getDeviceCode()).clusterKindVOS(clusterList).build());
        });
        return result;
    }

    /**
     * 根据电表设备code,获取电表信息
     *
     * @param deviceCode: 电表设备code
     */
    public MeterVO getMeterDataByDeviceCode(String deviceCode) {
        EmsDevice meterDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(meterDevice, FaultDesc.FAILURE_NOT_FOUNT.getDesc());
        List<MeterVO> result = this.getMeterDataByMeters(Lists.newArrayList(meterDevice));
        if (CollectionUtils.isNotEmpty(result)) {
            return result.get(0);
        }
        return MeterVO.builder().build();
    }

    /**
     * 获取储能装置下的电表数据
     */
    public List<MeterVO> getMeterData(String stationId, String equipmentId, Integer deviceType) {
        //查询电表有哪些
        List<EmsDevice> meterDevices = emsDeviceDAO.getListByCondition(stationId, equipmentId, deviceType);
        if(CollectionUtils.isEmpty(meterDevices)){
            return Collections.emptyList();
        }
        return this.getMeterDataByMeters(meterDevices);
    }

    /**
     * 获取电表数据
     */
    private List<MeterVO> getMeterDataByMeters(List<EmsDevice> meterDevices) {
        List<MeterVO> result = Lists.newArrayList();
        Map<String, Map<String, List<EmsProductLocationConfig>>> locationMap = emsProductLocationConfigDAO.getMapByLocation(LocationUrl.TWO_DIMENSIONAL_YC.getCode());
        //组装自己需要获取的实时数据信息
        List<EmsDeviceLocationVO> locationVOList = Lists.newArrayList();
        for (EmsDevice d : meterDevices) {
            List<EmsProductLocationConfig> configList = Lists.newArrayList();
            if(MapUtils.isNotEmpty(locationMap.get(d.getProductKey())) &&
                CollectionUtils.isNotEmpty(locationMap.get(d.getProductKey()).get(d.getModuleCode()))){
                configList.addAll(locationMap.get(d.getProductKey()).get(d.getModuleCode()));
            }
            locationVOList.addAll(this.getDeviceLocationVOByLocationAndConfig(d, configList));
        }
        //按照设备code分组,key:设备id
        Map<String, List<EmsDeviceLocationVO>> locationVOMap = locationVOList.stream().collect(Collectors.groupingBy(d -> d.getDeviceCode()));
        //调用查询实时数据接口
        Map<String, FlashDataVO> flashMap = this.getFlashMap(locationVOList);
        meterDevices.stream().forEach(d -> {
            List<EmsDeviceLocationVO> locationVOS = locationVOMap.get(d.getDeviceCode());
            List<List<FlashVO>> flashVOList = this.dealWithDeviceLocationByColumn(locationVOS,flashMap);
            result.add(MeterVO.builder().name(d.getDeviceName()).flashList(flashVOList).build());
        });
        return result;
    }

    /**
     * 获取BMU遥信数据
     * @param deviceCode: 簇设备code
     */
    public BMUYxVO getBamsOrBmuYxData(String deviceCode) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, FaultDesc.FAILURE_NOT_FOUNT.getDesc());
        Map<String, Map<String, List<EmsProductLocationConfig>>> locationMap = emsProductLocationConfigDAO.getMapByLocations(
                Lists.newArrayList(LocationUrl.STATE_YX.getCode(), LocationUrl.ALARM_YX.getCode(), LocationUrl.FAULT_YX.getCode()));
        //组装自己需要获取的实时数据信息
        List<EmsProductLocationConfig> configList = locationMap.get(emsDevice.getProductKey()).get(emsDevice.getModuleCode());
        List<EmsDeviceLocationVO> deviceLocationList = this.getDeviceLocationVOByLocationAndConfig(emsDevice, configList);
        //调用查询实时数据接口
        Map<String, FlashDataVO> flashMap = this.getFlashMap(deviceLocationList);
        Map<Integer,Object> locationTypeMap = this.getDeviceDataGroupByLocation(deviceLocationList,flashMap);
        return BMUYxVO.builder()
                .alarmYxs(locationTypeMap.get(LocationUrl.ALARM_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.ALARM_YX.getCode()))
                .faultYxs(locationTypeMap.get(LocationUrl.FAULT_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.FAULT_YX.getCode()))
                .stateYxs(locationTypeMap.get(LocationUrl.STATE_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.STATE_YX.getCode()))
                .build();
    }

    /**
     * 空调与液冷实时数据查询
     * @param stationId : 储能站id
     * @param equipmentId : 储能装置id
     */
    public List<AirConditionerVO> getAirConditionerInfo(String stationId, String equipmentId){
        List<AirConditionerVO> result = Lists.newArrayList();
        //查询空调设备
        List<EmsDevice> airDeviceList = emsDeviceDAO.getListByStationIdAndEquipmentIdAndDeviceTypes(stationId,equipmentId,
                Lists.newArrayList(DeviceType.AIR_CONDITIONER.getCode(),DeviceType.SURFACE.getCode()));
        if(CollectionUtils.isEmpty(airDeviceList)){
            return result;
        }
        return this.getAirConditionerInfoByDeviceCodes(airDeviceList);
    }

    /**
     * 获取单个空调或液冷实时数据
     * @param deviceCode: EMS设备编号
     */
    public AirConditionerVO getSingleAirConditionInfo(String deviceCode){
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice,"设备不存在！");
        List<AirConditionerVO> result = this.getAirConditionerInfoByDeviceCodes(Lists.newArrayList(emsDevice));
        if(CollectionUtils.isEmpty(result)){
            return AirConditionerVO.builder().build();
        }
        return result.get(0);
    }

    /**
     * 根据空调设备 获取空调需要展示的实时数据
     * @param airDeviceList : 空调设备集合
     * @return
     */
    private List<AirConditionerVO> getAirConditionerInfoByDeviceCodes(List<EmsDevice> airDeviceList){
        List<AirConditionerVO> result = Lists.newArrayList();
        //获取空调设备控制(遥调)所有展示数据
        List<DeviceYtShowVO> devicesYtByLocation = emsYkYtShowService.getDevicesYtByLocation(airDeviceList, YkYtLocationType.AIR_REMOTE_CONTROL.getCode());
        Map<String, DeviceYtShowVO> devicesYtShowMap = devicesYtByLocation.stream().collect(Collectors.toMap(DeviceYtShowVO::getDeviceCode, d->d,(p1, p2)->p1));
        //获取空调设备控制（遥控）所有展示数据
        List<DeviceYkShowVO> devicesYkByLocation = emsYkYtShowService.getDevicesYkByLocation(airDeviceList, YkYtLocationType.AIR_YK.getCode());
        Map<String,EmsDevice> deviceMap = airDeviceList.stream().collect(Collectors.toMap(EmsDevice::getDeviceCode,d->d));
        Map<String, DeviceYkShowVO> devicesYkMap= devicesYkByLocation.stream().collect(Collectors.toMap(DeviceYkShowVO::getDeviceCode,p->p,(p1,p2)->p1));
        Map<String, List<YkValShowVO>> devicesYkShowMap= devicesYkByLocation.stream().collect(Collectors.toMap(DeviceYkShowVO::getDeviceCode, DeviceYkShowVO::getShowVOS));
        for (String key:devicesYkMap.keySet()){
            EmsDevice device = deviceMap.get(key);
            DeviceYkShowVO deviceYkShowVO = devicesYkMap.get(key);
            this.FillYxRealDitInfo(device,Collections.singletonList(deviceYkShowVO));
        }
        //第一个key: productKey,第二个key: moduleCode
        Map<String, Map<String, List<EmsProductLocationConfig>>> locationMap = emsProductLocationConfigDAO.getMapByLocations(
                Lists.newArrayList(LocationUrl.ONE_DIMENSIONAL_YC.getCode(), LocationUrl.STATE_YX.getCode(), LocationUrl.FAULT_YX.getCode(),
                        LocationUrl.ALARM_YX.getCode()));
        //组装自己需要获取的实时数据信息
        List<EmsDeviceLocationVO> locationVOList = Lists.newArrayList();
        airDeviceList.stream().forEach(d->{
            if(MapUtils.isNotEmpty(locationMap.get(d.getProductKey())) && CollectionUtils.isNotEmpty(locationMap.get(d.getProductKey()).get(d.getModuleCode()))){
                List<EmsProductLocationConfig> configList = locationMap.get(d.getProductKey()).get(d.getModuleCode());
                locationVOList.addAll(this.getDeviceLocationVOByLocationAndConfig(d, configList));
            }
        });
        //按照设备code分组,key:设备id
        Map<String, List<EmsDeviceLocationVO>> locationVOMap = locationVOList.stream().collect(Collectors.groupingBy(d -> d.getDeviceCode()));
        //调用查询实时数据接口
        Map<String, FlashDataVO> flashMap = this.getFlashMap(locationVOList);
        //组装数据
        airDeviceList.stream().forEach(d->{
            List<EmsDeviceLocationVO> locationVOS = locationVOMap.get(d.getDeviceCode());
            //获取每个位置下的实时数据map
            Map<Integer,Object> locationTypeMap = this.getDeviceDataGroupByLocation(locationVOS,flashMap);
            result.add(AirConditionerVO.builder().name(d.getDeviceName()).deviceType(d.getDeviceType())
                    .ycFlashList(locationTypeMap.get(LocationUrl.ONE_DIMENSIONAL_YC.getCode()) ==null ?Collections.emptyList():(List<FlashVO>) locationTypeMap.get(LocationUrl.ONE_DIMENSIONAL_YC.getCode()))
                    .yxStateFlashList(locationTypeMap.get(LocationUrl.STATE_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.STATE_YX.getCode()))
                    .yxFaultFlashList(locationTypeMap.get(LocationUrl.FAULT_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.FAULT_YX.getCode()))
                    .yxAlarmFlashList(locationTypeMap.get(LocationUrl.ALARM_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.ALARM_YX.getCode()))
                    .ytDeviceController(devicesYtShowMap.get(d.getDeviceCode()) != null?devicesYtShowMap.get(d.getDeviceCode()).getShowVOS():Collections.emptyList())
                    .ykDeviceController(CollectionUtils.isNotEmpty(devicesYkShowMap.get(d.getDeviceCode()))?devicesYkShowMap.get(d.getDeviceCode()):Collections.emptyList())
                    .build());
        });
        return result;
    }

    /**
     * 获取辅助系统的 实时数据
     * 这个接口的原型需要修改，接口之后进行对应的修改
     * @param stationId : 储能站id
     * @param equipmentId : 储能装置id
     * @return
     */
    public List<AuxiliaryAndOtherDeviceVO> getAuxiliarySystemInfo(String stationId, String equipmentId){
        //查询辅助设备(不在为不同的辅助系统区分不同的设备,全部当成辅助子设备)
        List<EmsDevice> deviceList = emsDeviceDAO.getListByCondition(stationId, equipmentId,DeviceType.CHILD_AUXILIARY.getCode());
        if(CollectionUtils.isEmpty(deviceList)){
            return Collections.emptyList();
        }
        return this.getAuxiliaryOrOtherDeviceInfoByDeviceCodes(deviceList);
    }

    /**
     * 获取某个辅助设备数据
     */
    public AuxiliaryAndOtherDeviceVO getSingleAuxiliaryOrOtherDeviceInfo(String deviceCode){
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice,"设备不存在！");
        List<AuxiliaryAndOtherDeviceVO> result = this.getAuxiliaryOrOtherDeviceInfoByDeviceCodes(Lists.newArrayList(emsDevice));
        if(CollectionUtils.isEmpty(result)){
            return AuxiliaryAndOtherDeviceVO.builder().build();
        }
        return result.get(0);
    }

    /**
     * 获取多个辅助设备的实时数据
     * @param
     */
    public List<AuxiliaryAndOtherDeviceVO> getAuxiliaryOrOtherDeviceInfoByDeviceCodes(List<EmsDevice> deviceList){
        List<AuxiliaryAndOtherDeviceVO> auxiliaryAndOtherDeviceVOS = Lists.newArrayList();
        //获取辅助设备需要展示的遥控数据
        Map<String,EmsDevice> deviceMap = deviceList.stream().collect(Collectors.toMap(EmsDevice::getDeviceCode,d->d));
        List<DeviceYkShowVO> devicesYkByLocation = emsYkYtShowService.getDevicesYkByLocation(deviceList, YkYtLocationType.AUXILIARY_OTHER_YK.getCode());
        Map<String, DeviceYkShowVO> devicesYkMap= devicesYkByLocation.stream().collect(Collectors.toMap(DeviceYkShowVO::getDeviceCode,p->p,(p1,p2)->p1));
        for (String key:devicesYkMap.keySet()){
            EmsDevice device = deviceMap.get(key);
            DeviceYkShowVO deviceYkShowVO = devicesYkMap.get(key);
            this.FillYxRealDitInfo(device,Collections.singletonList(deviceYkShowVO));
        }
        //获取辅助设备需要展示的遥调数据
        List<DeviceYtShowVO> devicesYtByLocation = emsYkYtShowService.getDevicesYtByLocation(deviceList, YkYtLocationType.AUXILIARY_OTHER_YT.getCode());
        Map<String, DeviceYtShowVO> devicesYtMap= devicesYtByLocation.stream().collect(Collectors.toMap(DeviceYtShowVO::getDeviceCode,p->p,(p1,p2)->p1));
        //第一个key: productKey,第二个key: moduleCode
        Map<String, Map<String, List<EmsProductLocationConfig>>> locationMap = emsProductLocationConfigDAO.getMapByLocations(
                Lists.newArrayList(LocationUrl.TWO_DIMENSIONAL_YC.getCode(), LocationUrl.STATE_YX.getCode(),LocationUrl.FAULT_YX.getCode(),
                        LocationUrl.ALARM_YX.getCode()));
        //组装自己需要获取的实时数据信息
        List<EmsDeviceLocationVO> locationVOList = Lists.newArrayList();
        deviceList.stream().forEach(d->{
            if(MapUtils.isNotEmpty(locationMap.get(d.getProductKey())) && CollectionUtils.isNotEmpty(locationMap.get(d.getProductKey()).get(d.getModuleCode()))){
                List<EmsProductLocationConfig> configList = locationMap.get(d.getProductKey()).get(d.getModuleCode());
                locationVOList.addAll(this.getDeviceLocationVOByLocationAndConfig(d, configList));
            }
        });
        //按照设备code分组,key:设备id
        Map<String, List<EmsDeviceLocationVO>> locationVOMap = locationVOList.stream().collect(Collectors.groupingBy(d -> d.getDeviceCode()));
        //调用查询实时数据接口
        Map<String, FlashDataVO> flashMap = this.getFlashMap(locationVOList);
        //组装数据
        for (EmsDevice d : deviceList){
            List<EmsDeviceLocationVO> locationVOS = locationVOMap.get(d.getDeviceCode());
            DeviceDataVO kindVO = DeviceDataVO.builder().build();
            if(CollectionUtils.isEmpty(locationVOS)){
                kindVO.setYkControlList(devicesYkMap.get(d.getDeviceCode()) == null? Lists.newArrayList() : devicesYkMap.get(d.getDeviceCode()).getShowVOS());
                kindVO.setYcFlashList(Collections.emptyList());
                kindVO.setYxStateFlashList(Collections.emptyList());
                kindVO.setYxFaultFlashList(Collections.emptyList());
                kindVO.setYxAlarmFlashList(Collections.emptyList());
                //遥调数据
                kindVO.setYtControlList(devicesYtMap.get(d.getDeviceCode()) == null? Lists.newArrayList() : devicesYtMap.get(d.getDeviceCode()).getShowVOS());
                //订阅数据
                kindVO.setSubscribePids(devicesYtMap.get(d.getDeviceCode()) == null? Lists.newArrayList() : devicesYtMap.get(d.getDeviceCode()).getSubscribePids());
                auxiliaryAndOtherDeviceVOS.add(AuxiliaryAndOtherDeviceVO.builder().name(d.getDeviceName()).childAuxiliaryVO(kindVO).build());
                continue;
            }
            Map<Integer,Object> locationTypeMap = this.getDeviceDataGroupByLocation(locationVOS,flashMap);
            kindVO.setYcFlashList(locationTypeMap.get(LocationUrl.TWO_DIMENSIONAL_YC.getCode()) ==null ?Collections.emptyList():(List<List<FlashVO>>) locationTypeMap.get(LocationUrl.TWO_DIMENSIONAL_YC.getCode()));
            kindVO.setYxStateFlashList(locationTypeMap.get(LocationUrl.STATE_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.STATE_YX.getCode()));
            kindVO.setYxFaultFlashList(locationTypeMap.get(LocationUrl.FAULT_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.FAULT_YX.getCode()));
            kindVO.setYxAlarmFlashList(locationTypeMap.get(LocationUrl.ALARM_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.ALARM_YX.getCode()));
            //遥控数据
            kindVO.setYkControlList(devicesYkMap.get(d.getDeviceCode()) == null? Lists.newArrayList() : devicesYkMap.get(d.getDeviceCode()).getShowVOS());
            //遥调数据
            kindVO.setYtControlList(devicesYtMap.get(d.getDeviceCode()) == null? Lists.newArrayList() : devicesYtMap.get(d.getDeviceCode()).getShowVOS());
            //订阅数据
            kindVO.setSubscribePids(devicesYtMap.get(d.getDeviceCode()) == null? Lists.newArrayList() : devicesYtMap.get(d.getDeviceCode()).getSubscribePids());
            auxiliaryAndOtherDeviceVOS.add(AuxiliaryAndOtherDeviceVO.builder().name(d.getDeviceName()).childAuxiliaryVO(kindVO).build());
        }
        return auxiliaryAndOtherDeviceVOS;
    }

    /**
     * 获取SVG图中的实测点号的实时数据
     */
    public List<FlashDataVO> getSvgFlashVO(String jsonData){
        List<String[]> list = JSON.parseArray(jsonData,String[].class);
        //String[0] : deviceCode ,String[1] : dit
        List<QueryDataVO> queryDataVOS = Lists.newArrayList();
        list.stream().forEach(d-> queryDataVOS.add(QueryDataVO.builder().initDeviceCode(d[0]).dit(d[1]).build()));
        queryDataVOS.stream().forEach(d-> d.setPid(d.getInitDeviceCode() + SysConstant.SPOT + d.getDit()));
        List<FlashDataVO> queryResult = queryFlashDataCommonService.getFlashData(queryDataVOS);
        queryResult.stream().forEach(d-> d.setSvgKey(new String[]{d.getInitDeviceCode(),d.getDit(),d.getMeasureType()+""}));
        return queryResult;
    }

    public List<FlashDataVO> getSvgFlashVO(List<DitDataVO> list){
        List<QueryDataVO> flashDataVOS = list.stream().filter(d->DitTypeEnum.isFlashData(d.getDitType()))
                .map(d->QueryDataVO.builder().initDeviceCode(d.getInitDeviceCode())
                        .dit(d.getDit()).pid(d.getInitDeviceCode() + SysConstant.SPOT + d.getDit()).build()).collect(Collectors.toList());
        List<QueryDataVO> calDataVOS = list.stream().filter(d->DitTypeEnum.isCalData(d.getDitType()))
                .map(d->QueryDataVO.builder().initDeviceCode(d.getInitDeviceCode())
                        .dit(d.getDit()).pid(d.getInitDeviceCode() + SysConstant.SPOT + d.getDit()).build()).collect(Collectors.toList());
        List<FlashDataVO> flashResult = queryFlashDataCommonService.getFlashData(flashDataVOS);
        List<FlashDataVO> calResult = queryCalDataCommonService.getCalData(calDataVOS);
        flashResult.stream().forEach(d-> d.setDitType(Objects.equals(MeasureType.yc.getCode(),d.getMeasureType())?DitTypeEnum.YC.getCode():DitTypeEnum.YX.getCode()));
        calResult.stream().forEach(d-> d.setDitType(Objects.equals(MeasureType.yc.getCode(),d.getMeasureType())?DitTypeEnum.CAL_YC.getCode():DitTypeEnum.CAL_YX.getCode()));
        //把计算数据的实时数据加入到实时数据的list中
        flashResult.addAll(calResult );
        return flashResult;
    }

    /**
     * 获取保护设备的 实时数据
     * @param stationId : 储能站id
     * @param equipmentId : 储能装置id
     * @return
     */
    public List<ProtectDeviceVO> getProtectDeviceInfo(String stationId, String equipmentId){
        //查询保护设备
        List<EmsDevice> deviceList = emsDeviceDAO.getListByCondition(stationId, equipmentId,DeviceType.CHILD_PROTECT_DEVICE.getCode());
        if(CollectionUtils.isEmpty(deviceList)){
            return Collections.emptyList();
        }
        return this.getProtectDeviceInfoByDeviceCodes(deviceList);
    }

    /**
     * 获取单个保护设备数据
     * @param deviceCode
     */
    public ProtectDeviceVO getSingleProtectDeviceData(String deviceCode){
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice,"设备不存在！");
        List<ProtectDeviceVO> result = this.getProtectDeviceInfoByDeviceCodes(Lists.newArrayList(emsDevice));
        if(CollectionUtils.isEmpty(result)){
            return ProtectDeviceVO.builder().build();
        }
        return result.get(0);
    }

    /**
     * 获取储能站下的控制器数据
     * @param stationId
     */
    public List<ControlVO> getControlData(String stationId){
        //查询保护设备
        List<EmsDevice> deviceList = emsDeviceDAO.getListByCondition(stationId, null,DeviceType.CONTROL.getCode());
        if(CollectionUtils.isEmpty(deviceList)){
            return Collections.emptyList();
        }
        return this.getControlDataByDeviceCodes(deviceList);
    }

    /**
     * 获取单个控制器数据
     * @param deviceCode : EMS设备编号
     */
    public ControlVO getSingleControlData(String deviceCode){
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice,"设备不存在！");
        List<ControlVO> result = this.getControlDataByDeviceCodes(Lists.newArrayList(emsDevice));
        if(CollectionUtils.isEmpty(result)){
            return ControlVO.builder().build();
        }
        return result.get(0);
    }

    /**
     * 获取多个保护设备数据
     * @param deviceList
     * @return
     */
    public List<ProtectDeviceVO> getProtectDeviceInfoByDeviceCodes(List<EmsDevice> deviceList){
        List<ProtectDeviceVO> protectDeviceList = Lists.newArrayList();
        //获取保护设备需要展示的遥控数据
        Map<String,EmsDevice> deviceMap = deviceList.stream().collect(Collectors.toMap(EmsDevice::getDeviceCode,d->d));
        List<DeviceYkShowVO> devicesYkByLocation = emsYkYtShowService.getDevicesYkByLocation(deviceList, YkYtLocationType.PROTECT_DEVICE_YK.getCode());
        Map<String, DeviceYkShowVO> devicesYkMap= devicesYkByLocation.stream().collect(Collectors.toMap(DeviceYkShowVO::getDeviceCode,p->p,(p1,p2)->p1));
        for (String key:devicesYkMap.keySet()){
            EmsDevice device = deviceMap.get(key);
            DeviceYkShowVO deviceYkShowVO = devicesYkMap.get(key);
            this.FillYxRealDitInfo(device,Collections.singletonList(deviceYkShowVO));
        }
        //获取保护设备需要展示的遥调数据
        List<DeviceYtShowVO> devicesYtByLocation = emsYkYtShowService.getDevicesYtByLocation(deviceList, YkYtLocationType.PROTECT_DEVICE_YT.getCode());
        Map<String, DeviceYtShowVO> devicesYtMap= devicesYtByLocation.stream().collect(Collectors.toMap(DeviceYtShowVO::getDeviceCode,p->p,(p1,p2)->p1));
        //获取保护设备需要展示的保护定值
        List<DeviceYtShowVO> constantValueByLocation = emsYkYtShowService.getDevicesYtByLocation(deviceList, YkYtLocationType.PROTECT_DEVICE_CONSTANT_VALUE.getCode());
        Map<String, DeviceYtShowVO> constantValueMap= constantValueByLocation.stream().collect(Collectors.toMap(DeviceYtShowVO::getDeviceCode,p->p,(p1,p2)->p1));
        //第一个key: productKey,第二个key: moduleCode
        Map<String, Map<String, List<EmsProductLocationConfig>>> locationMap = emsProductLocationConfigDAO.getMapByLocations(
                Lists.newArrayList(LocationUrl.TWO_DIMENSIONAL_YC.getCode(), LocationUrl.STATE_YX.getCode(),LocationUrl.FAULT_YX.getCode(),
                        LocationUrl.ALARM_YX.getCode(),LocationUrl.PROTECT_EVENT_YX.getCode()));
        //组装自己需要获取的实时数据信息
        List<EmsDeviceLocationVO> locationVOList = Lists.newArrayList();
        deviceList.stream().forEach(d->{
            if(MapUtils.isNotEmpty(locationMap.get(d.getProductKey())) && CollectionUtils.isNotEmpty(locationMap.get(d.getProductKey()).get(d.getModuleCode()))){
                List<EmsProductLocationConfig> configList = locationMap.get(d.getProductKey()).get(d.getModuleCode());
                locationVOList.addAll(this.getDeviceLocationVOByLocationAndConfig(d, configList));
            }
        });
        //按照设备code分组,key:设备id
        Map<String, List<EmsDeviceLocationVO>> locationVOMap = locationVOList.stream().collect(Collectors.groupingBy(d -> d.getDeviceCode()));
        //调用查询实时数据接口
        Map<String, FlashDataVO> flashMap = this.getFlashMap(locationVOList);
        //组装数据
        for (EmsDevice d : deviceList){
            List<EmsDeviceLocationVO> locationVOS = locationVOMap.get(d.getDeviceCode());
            if(CollectionUtils.isEmpty(locationVOS)){
                continue;
            }
            Map<Integer,Object> locationTypeMap = this.getDeviceDataGroupByLocation(locationVOS,flashMap);
            ProtectDeviceVO protectDeviceVO = ProtectDeviceVO.builder().name(d.getDeviceName()).subscribePids(Lists.newArrayList()).build();
            protectDeviceVO.setYcFlashList(locationTypeMap.get(LocationUrl.TWO_DIMENSIONAL_YC.getCode()) ==null ?Collections.emptyList():(List<List<FlashVO>>) locationTypeMap.get(LocationUrl.TWO_DIMENSIONAL_YC.getCode()));
            protectDeviceVO.setYxStateFlashList(locationTypeMap.get(LocationUrl.STATE_YX.getCode()) ==null ?Collections.emptyList():(List<FlashVO>) locationTypeMap.get(LocationUrl.STATE_YX.getCode()));
            protectDeviceVO.setYxFaultFlashList(locationTypeMap.get(LocationUrl.FAULT_YX.getCode()) ==null ?Collections.emptyList():(List<FlashVO>) locationTypeMap.get(LocationUrl.FAULT_YX.getCode()));
            protectDeviceVO.setYxAlarmFlashList(locationTypeMap.get(LocationUrl.ALARM_YX.getCode()) ==null ?Collections.emptyList():(List<FlashVO>) locationTypeMap.get(LocationUrl.ALARM_YX.getCode()));
            protectDeviceVO.setProtectEventFlashList(locationTypeMap.get(LocationUrl.PROTECT_EVENT_YX.getCode()) ==null ?Collections.emptyList():(List<FlashVO>) locationTypeMap.get(LocationUrl.PROTECT_EVENT_YX.getCode()));
            //遥控数据
            protectDeviceVO.setYkControlList(devicesYkMap.get(d.getDeviceCode()) == null? Collections.emptyList() : devicesYkMap.get(d.getDeviceCode()).getShowVOS());
            //遥调数据
            protectDeviceVO.setYtControlList(devicesYtMap.get(d.getDeviceCode()) == null? Collections.emptyList() : devicesYtMap.get(d.getDeviceCode()).getShowVOS());
            //保护定值
            protectDeviceVO.setConstantValueList(constantValueMap.get(d.getDeviceCode()) == null? Collections.EMPTY_LIST : constantValueMap.get(d.getDeviceCode()).getShowVOS());
            //订阅数据
            if(devicesYtMap.get(d.getDeviceCode()) != null){
                protectDeviceVO.getSubscribePids().addAll(devicesYtMap.get(d.getDeviceCode()).getSubscribePids());
            }
            if(constantValueMap.get(d.getDeviceCode()) != null){
                protectDeviceVO.getSubscribePids().addAll(constantValueMap.get(d.getDeviceCode()).getSubscribePids());
            }
            protectDeviceList.add(protectDeviceVO);
        }
        return protectDeviceList;
    }

    /**
     * 获取控制器设备数据
     * @param deviceList
     */
    public List<ControlVO> getControlDataByDeviceCodes(List<EmsDevice> deviceList){
        List<ControlVO> controlList = Lists.newArrayList();
        Map<String,EmsDevice> deviceMap = deviceList.stream().collect(Collectors.toMap(EmsDevice::getDeviceCode,d->d));
        //获取控制器设备需要展示的遥控数据
        List<DeviceYkShowVO> devicesYkByLocation = emsYkYtShowService.getDevicesYkByLocation(deviceList, YkYtLocationType.CONTROL_YK.getCode());
        Map<String, DeviceYkShowVO> devicesYkMap= devicesYkByLocation.stream().collect(Collectors.toMap(DeviceYkShowVO::getDeviceCode,p->p,(p1,p2)->p1));
        for (String key:devicesYkMap.keySet()){
            EmsDevice device = deviceMap.get(key);
            DeviceYkShowVO deviceYkShowVO = devicesYkMap.get(key);
            this.FillYxRealDitInfo(device,Collections.singletonList(deviceYkShowVO));
        }
        //获取控制器设备需要展示的遥调数据
        List<DeviceYtShowVO> devicesYtByLocation = emsYkYtShowService.getDevicesYtByLocation(deviceList, YkYtLocationType.CONTROL_YT.getCode());
        Map<String, DeviceYtShowVO> devicesYtMap= devicesYtByLocation.stream().collect(Collectors.toMap(DeviceYtShowVO::getDeviceCode,p->p,(p1,p2)->p1));
        //第一个key: productKey,第二个key: moduleCode
        Map<String, Map<String, List<EmsProductLocationConfig>>> locationMap = emsProductLocationConfigDAO.getMapByLocations(
                Lists.newArrayList(LocationUrl.CONTROL_GROUP_ONE_YC.getCode(), LocationUrl.CONTROL_GROUP_TWO_YC.getCode(),LocationUrl.ONE_DIMENSIONAL_YC.getCode(),
                        LocationUrl.STATE_YX.getCode(),LocationUrl.FAULT_YX.getCode(), LocationUrl.ALARM_YX.getCode()));
        //组装自己需要获取的实时数据信息
        List<EmsDeviceLocationVO> locationVOList = Lists.newArrayList();
        deviceList.stream().forEach(d->{
            if(MapUtils.isNotEmpty(locationMap.get(d.getProductKey())) && CollectionUtils.isNotEmpty(locationMap.get(d.getProductKey()).get(d.getModuleCode()))){
                List<EmsProductLocationConfig> configList = locationMap.get(d.getProductKey()).get(d.getModuleCode());
                locationVOList.addAll(this.getDeviceLocationVOByLocationAndConfig(d, configList));
            }
        });
        //按照设备code分组,key:设备id
        Map<String, List<EmsDeviceLocationVO>> locationVOMap = locationVOList.stream().collect(Collectors.groupingBy(d -> d.getDeviceCode()));
        //调用查询实时数据接口
        Map<String, FlashDataVO> flashMap = this.getFlashMap(locationVOList);
        for (EmsDevice d : deviceList){
            List<EmsDeviceLocationVO> locationVOS = locationVOMap.get(d.getDeviceCode());
            if(CollectionUtils.isEmpty(locationVOS)){
                continue;
            }
            //组装单个控制器的数据
            Map<Integer,Object> locationTypeMap = this.getDeviceDataGroupByLocation(locationVOS,flashMap);
            ControlVO controlVO = ControlVO.builder().name(d.getDeviceName()).subscribePids(Lists.newArrayList()).build();
            controlVO.setYcGroupOneFlashList(locationTypeMap.get(LocationUrl.CONTROL_GROUP_ONE_YC.getCode()) ==null ?Collections.emptyList():(List<FlashVO>) locationTypeMap.get(LocationUrl.CONTROL_GROUP_ONE_YC.getCode()));
            controlVO.setYcGroupTwoFlashList(locationTypeMap.get(LocationUrl.CONTROL_GROUP_TWO_YC.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.CONTROL_GROUP_TWO_YC.getCode()));
            controlVO.setYcOtherFlashList(locationTypeMap.get(LocationUrl.ONE_DIMENSIONAL_YC.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.ONE_DIMENSIONAL_YC.getCode()));
            controlVO.setYxStateFlashList(locationTypeMap.get(LocationUrl.STATE_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.STATE_YX.getCode()));
            controlVO.setYxFaultFlashList(locationTypeMap.get(LocationUrl.FAULT_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.FAULT_YX.getCode()));
            controlVO.setYxAlarmFlashList(locationTypeMap.get(LocationUrl.ALARM_YX.getCode()) == null?Collections.emptyList():(List<FlashVO>)locationTypeMap.get(LocationUrl.ALARM_YX.getCode()));
            //遥控数据
            controlVO.setYkControlList(devicesYkMap.get(d.getDeviceCode()) == null? Lists.newArrayList() : devicesYkMap.get(d.getDeviceCode()).getShowVOS());
            //遥调数据
            controlVO.setYtControlList(devicesYtMap.get(d.getDeviceCode()) == null? Lists.newArrayList() : devicesYtMap.get(d.getDeviceCode()).getShowVOS());
            //订阅数据
            if(devicesYtMap.get(d.getDeviceCode()) != null){
                controlVO.getSubscribePids().addAll(devicesYtMap.get(d.getDeviceCode()).getSubscribePids());
            }
            controlList.add(controlVO);
        }
        return controlList;
    }

    private void FillYxRealDitInfo(EmsDevice device,List<DeviceYkShowVO> deviceYkShowVOS) {
        String productKey = device.getProductKey();
        List<String> ykDits = Lists.newArrayList();
        for (int i = 0 ; i < deviceYkShowVOS.size() ; i++){
            DeviceYkShowVO showVO = deviceYkShowVOS.get(i);
            ykDits.addAll(showVO.getShowVOS().stream().map(YkValShowVO::getRemoteDit).collect(Collectors.toList()));
        }
        //获取配置了实时反馈yx点号的yk点号信息
        List<IotProductYkYtDit> iotProductYkYtDits = iotProductYkYtDitDAO.selectListByProductKeysAndDits(Collections.singletonList(productKey),ykDits).stream().filter(d->d.getActualDit()!=null).collect(Collectors.toList());
        Map<String,String> YkYxRelationMap = iotProductYkYtDits.stream().collect(Collectors.toMap(IotProductYkYtDit::getDit,IotProductYkYtDit::getActualDit));
        List<DitDataVO> ditDataVOS = Lists.newArrayList();
        iotProductYkYtDits.forEach(d->{
            DitDataVO ditDataVO = new DitDataVO();
            ditDataVO.setDit(d.getActualDit());
            ditDataVO.setInitDeviceCode(device.getInitDeviceCode());
            ditDataVO.setDitType(DitTypeEnum.YX.getCode());
            ditDataVOS.add(ditDataVO);
        });
        List<FlashDataVO> flashYxDataVOS = this.getSvgFlashVO(ditDataVOS);
        Map<String,FlashDataVO> yxDataMap = flashYxDataVOS.stream().collect(Collectors.toMap(FlashDataVO::getDit,d->d));
        //把查到的yx实时数据填入对应的yk对象信息中返回
        deviceYkShowVOS.forEach(d->{
            d.getShowVOS().forEach(v->{
                String keyYk = v.getRemoteDit();
                String keyYx = YkYxRelationMap.get(keyYk);
                if (keyYx!=null){
                    FlashDataVO yxData = yxDataMap.get(keyYx);
                    v.setYxRealDitVO(yxData);
                }
            });
        });
    }

    /**
     * 组装单个设备的实时数据,并根据不同的位置(LocationUrl枚举)分组
     * @param locationVOList: 单个设备需要展示的全部点号数据信息集合
     * @param flashMap: 实时数据查询结果集
     * @return
     */
    private Map<Integer,Object> getDeviceDataGroupByLocation(List<EmsDeviceLocationVO> locationVOList,Map<String, FlashDataVO> flashMap){
        //存储不同位置下的实时数据,key：LocationUrl枚举中的code
        Map<Integer,Object> result = Maps.newHashMap();
        Map<Integer, List<EmsDeviceLocationVO>> locationMap = locationVOList.stream().collect(Collectors.groupingBy(f -> f.getLocation()));
        locationMap.forEach((k,v)->{
            if(LocationUrl.fromCode(k).getDimensionalType() == DimensionalType.ONE_DIMENSIONAL){
                //如果该位置的排序是一维的，返回对象为List<FlashVO>
                //按照顺序从小到大
                v = v.stream().sorted(Comparator.comparing(EmsDeviceLocationVO::getRow)).collect(Collectors.toList());
                List<FlashVO> flashVOS = v.stream().map(d-> this.getFlashVO(d,flashMap)).collect(Collectors.toList());
                result.put(k,flashVOS);
            }else{
                //位置为二维排序，返回对象为List<List<FlashVO>>
                result.put(k,this.dealWithDeviceLocationByColumn(v,flashMap));
            }
        });
        //设置动画状态
        Object alarmObj = result.get(LocationUrl.ALARM_YX.getCode());
        Object faultObj = result.get(LocationUrl.FAULT_YX.getCode());
        List<FlashVO> flashVOS = setAnimateForFaultOrAlarm(faultObj);
        List<FlashVO> alarmVOS = setAnimateForFaultOrAlarm(alarmObj);
        result.put(LocationUrl.ALARM_YX.getCode(),alarmVOS);
        result.put(LocationUrl.FAULT_YX.getCode(),flashVOS);
        return result;
    }

}
